`timescale 1ns / 1ps
/************************************************************\
 **  Copyright (c) 2022-2023 Gonsin, Inc.
 **  All Right Reserved.
 **  Author: http://www.anlogic.com/
 **  Description: temac_block
 **  Rev 1.0
\************************************************************/

module temac_block #(
parameter P_ADD_FILT_EN = 1'b1,   // 如果为true，则内核支持地址过滤。
parameter P_ADD_FILT_LIST = 16,		// 内核支持的地址表可配置地址个数
parameter P_HALF_DUPLEX = 1'b1,		// 如果为true，则内核半双工和全双工模式，否则仅支持全双工模式。
parameter P_HOST_EN = 1'b1,		    // 如果为true，则内核仅支持AXI接口管理配置，否则内核仅支持矢量总线配置。
parameter P_SPEED_1000 = 1'b0,		// 如果为true，则内核仅支持1000 Mbps速度。
parameter P_SPEED_10_100 = 1'b0,	// 如果为true，则内核仅支持10/100 Mbps速度。
parameter P_TRI_SPEED = 1'b1		  // 如果为true，则内核支持3速
)
(
// 异步复位
//--------------------------
input reset_i,

//全局发送时钟
//--------------------------
input gtx_clk_i,

// 客户端接收接口
//--------------------------
output rx_clk_o,
output rx_clkEn_o,
output [7:0] rxdata8b_o,
output rxdata_valid_o,
output rx_correctFrame_o,
output rx_errorFrame_o,
output [26:0] rx27b_statusVector_o,
output rx_statusVld_o,

// 客户发送器接口
//-----------------------------
output tx_clk_o,
output tx_clken_o,
input [7:0] txdata8b_i,
input txdata_en_i,
output tx_rdy_o,
input tx_stop_i,
output tx_collision_o,
output tx_retransmit_o,
input [7:0] tx8b_ifgVal_i,
output [28:0] tx29b_statusVector_o,
output tx_statusVld_o,

// 流控接口
//----------------------
input pause_req_i,
input [15:0] pause16b_val_i,
input [47:0] pause48b_sourceAddr_i,

// 初始默认单播地址值
//----------------
input [47:0] unicast48b_address_i,

// AXI主机管理接口
//---------------
input sAXI_aclk_i,
input [7:0] sAXI8b_awaddr_i,
input sAXI_awvalid_i,
output sAXI_awready_o,
input [31:0] sAXI32b_wdata_i,   
input sAXI_wvalid_i,
output sAXI_wready_o,
output [1:0] sAXI2b_bresp_o,
output sAXI_bvalid_o,
input sAXI_bready_i,
input [7:0] sAXI8b_araddr_i,
input sAXI_arvalid_i,
output sAXI_arready_o,
output [31:0] sAXI32b_rdata_o,
output [1:0] sAXI2b_rresp_o,
output sAXI_rvalid_o,
input sAXI_rready_i,

// 向量配置总线
//----------------
input [19:0] mac20b_cfgVector_i,

// RGMII接口
//----------------
output [3:0] rgmii4b_txd_o,
output rgmii_txCtl_o,
output rgmii_txc_o,
input [3:0] rgmii4b_rxd_i,
input rgmii_rxCtl_i,
input rgmii_rxc_i,
output inband_linkStatus_o,
output [1:0] inband2b_clockSpeed_o,
output inband_duplexStatus_o,

// MDIO接口
//---------------
input mdio_i,
output mdio_o,
output mdio_oen_o,
output mdio_clk_o
);
      
//-------------------------------------------------------------------------------------------------------------
// 模块内部信号。
//-------------------------------------------------------------------------------------------------------------

//复位信号
//-----------------------
wire tx_reset_w;    // MAC核和rgmii接口模块 Tx域中的同步复位
wire rx_reset_w;    // MAC核和rgmii接口模块 rx域中的同步复位
   
//rx域 接收时钟 及 用户接收时钟使能信号
//-----------------------
wire rx_rgmii_clkInt_w;       // RGMII 接收时钟.              
reg client_rxcEn_int;         // 客户端接收时钟使能信号
   
//tx域 发送时钟使能信号
//-----------------------  
wire client_txcEn_int_w;         // 客户端发送时钟使能信号
wire gmii_txcEn_int_w;           // gmii/mii接口发送时钟使能信号
wire rgmii_txcEn_w;              // rgmii接口发送时钟使能信号，  输入到ODDR-d1端口
wire rgmii_txcEn_shift_w;        // rgmii接口发送时钟使能信号，  输入到ODDR-d0端口

//速度指示信号
//-----------------------
wire speed10_int_w;              // 当前速度在 10Mb/s.
wire speed100_int_w;             // 当前速度在 100Mb/s.
wire speed1000_int_w;            // 当前速度在 1000Mb/s.   
wire speed10_100_int_w;          // 当前速度在 10Mb/s 或 100Mb/s.
wire speed10_100_w;              

//模块内部 gmii/mii 信号
//-----------------------
wire gmii_txenInt_w;            
wire gmii_txerInt_w;            
wire [7:0] gmii8b_txdInt_w;              
wire gmii_rxdvInt_w;            
wire gmii_rxerInt_w;            
wire [7:0] gmii8b_rxdInt_w;              
wire gmii_colInt_w;              
wire gmii_crsInt_w;
      
//==================================================================================================================

//-----------------------------
//速度指示信号
//speed10_100_int_w = ！speed_1000_int;
assign speed10_100_int_w = speed10_int_w | speed100_int_w;  // "1" 指示 10Mb/s 或 100Mb/s 速度运行; "0" 指示 1000Mb/s速度运行

//-----------------------------
// 将 时钟信号/时钟使能信号 输出给用户.
assign rx_clk_o = rx_rgmii_clkInt_w;        // 125MHz（1Gbps） 25MHz(100Mbps)  2.5MHz(10Mbps)
assign tx_clk_o = gtx_clk_i;                // 125MHz
assign rx_clkEn_o = client_rxcEn_int;       // 保持1 （1Gbps） 12.5MHz(100Mbps)  1.25MHz(10Mbps)
assign tx_clken_o = client_txcEn_int_w;     // 保持1 （1Gbps） 12.5MHz(100Mbps)  1.25MHz(10Mbps)
 
//---------------------------------------------------------------------------
// 例化 复位同步
//---------------------------------------------------------------------------

// 在Tx时钟域中生成同步复位信号
reset_sync tx_reset_gen 
(
  .clk_i(gtx_clk_i),
  .enable_i(1'b1),
  .reset_i(reset_i),
  .reset_o(tx_reset_w)
);

// 在rx时钟域中生成同步复位信号
reset_sync rx_reset_gen 
(
  .clk_i(rx_rgmii_clkInt_w),
  .enable_i(1'b1),
  .reset_i(reset_i),
  .reset_o(rx_reset_w)
);
  
//---------------------------------------------------------------------------
// Clock 产生
//---------------------------------------------------------------------------
// 如果外接 RGMII接口 , GTX_CLK 总是 125MHz，
// 接收的PHY芯片时钟rx_rgmii_clk_int为：125MHz（1Gbps） 25MHz(100Mbps)  2.5MHz(10Mbps)
// 对应三速的时钟如下：
//
//                              1G ethernet       100 MHz        10 MHz
//            CORE tx/rx CLK     125   MHz       12.5 MHz     1.25  MHz
//              GMII/MII CLK     125   MHz       25   MHz     2.5   MHz
//                 RGMII CLK     125   MHz       25   MHz     2.5   MHz
//
//  100/10Mbp速度下， GMII/RGMII接口为4位有效数据位宽，客户端8位数据位宽接口，
//                    client_tx_enable 为 gmii/rgmii_tx_enable 频率的1/2
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// 发送器时钟使能信号产生逻辑。 产生 10/100/1000速度对应时钟 的使能信号。
//---------------------------------------------------------------------------

tx_clk_en_gen tx_clk_en_gen_u (
.reset_i(tx_reset_w), 
.speed10_100_i(speed10_100_int_w), 
.speed100_i(speed100_int_w),
.clk_i(gtx_clk_i),                        //input 125MHz
.client_txcen_o(client_txcEn_int_w),      //output 保持1（1Gbps） 12.5MHz(100Mbps)  1.25MHz(10Mbps) ；使能信号 一个周期（8ns）高电平
.gmii_txcen_o(gmii_txcEn_int_w),          //output 保持1（1Gbps） 25MHz(100Mbps)    2.5MHz(10Mbps)  ；使能信号 一个周期（8ns）高电平
.rgmii_txcen_o(rgmii_txcEn_w),            //output 保持1（1Gbps） 25MHz(100Mbps)    2.5MHz(10Mbps)  ；在rgmii_interface模块中输入给ODDR
.rgmii_txcen_shift_o(rgmii_txcEn_shift_w) //output 保持1（1Gbps） 25MHz(100Mbps)    2.5MHz(10Mbps)  ；在rgmii_interface模块中输入给ODDR
);

//---------------------------------------------------------------------------
// 接收器时钟使能信号产生逻辑
//---------------------------------------------------------------------------
// 在接收器时钟域中重新同步速度选择使能信号

sync_block speed_10_100_rx_sync 
(
  .clk_i(rx_rgmii_clkInt_w),    // 125MHz（1Gbps） 25MHz(100Mbps)  2.5MHz(10Mbps)
  .data_i(speed10_100_int_w),
  .data_o(speed10_100_w)
);

// 产生客户端接收时钟使能信号

always@(posedge rx_rgmii_clkInt_w) begin  // 125MHz（1Gbps） 25MHz(100Mbps)  2.5MHz(10Mbps)
  if (rx_reset_w == 1'b1) begin
    client_rxcEn_int <= 1'b0;
  end
  else begin     // client_rxc_en_int： 保持1（1Gbps） 12.5MHz(100Mbps)  1.25MHz(10Mbps)
    if (speed10_100_w == 1'b1)
      client_rxcEn_int <= ~(client_rxcEn_int); 
    else
      client_rxcEn_int <= 1'b1;
  end
end

//---------------------------------------------------------------------------
// 例化 rgmii interface
//---------------------------------------------------------------------------
rgmii_interface rgmii_interface_u (
// 同步复位
.tx_reset_i(tx_reset_w),
.rx_reset_i(rx_reset_w),

// 指示当前运行速度
.speed10_100_i(speed10_100_int_w),

// 以下端口是RGMII物理接口：这些端口将位于FPGA的引脚上
.rgmii4b_txd_o(rgmii4b_txd_o),
.rgmii_txCtl_o(rgmii_txCtl_o),
.rgmii_txc_o(rgmii_txc_o),
.rgmii4b_rxd_i(rgmii4b_rxd_i),
.rgmii_rxCtl_i(rgmii_rxCtl_i),
.rgmii_rxc_i(rgmii_rxc_i),

//以下信号为RGMII状态信号
.link_status_o(inband_linkStatus_o),
.clock2b_speed_o(inband2b_clockSpeed_o),
.duplex_status_o(inband_duplexStatus_o),

// 以下端口连接到 TEMAC核 的 内部GMII接口模块
//.gmii_txcen_i(gmii_txcEn_int_w),
.gmii8b_txd_i(gmii8b_txdInt_w),
.gmii_txen_i(gmii_txenInt_w),
.gmii_txer_i(gmii_txerInt_w),
.gmii_crs_o(gmii_crsInt_w),
.gmii_col_o(gmii_colInt_w),
.gmii8b_rxd_o(gmii8b_rxdInt_w),
.gmii_rxdv_o(gmii_rxdvInt_w),
.gmii_rxer_o(gmii_rxerInt_w),

//发送时钟信号
.tx_clk_i(gtx_clk_i),
.rgmii_txcen_i(rgmii_txcEn_w),
.rgmii_txcen_shift_i(rgmii_txcEn_shift_w),

//MAC核 和 客户端逻辑 的接收器时钟
.rx_rgmii_clk_o(rx_rgmii_clkInt_w)  //output：125MHz（1Gbps） 25MHz(100Mbps)  2.5MHz(10Mbps)
);

//---------------------------------------------------------------------------
// 例化 temac core
//---------------------------------------------------------------------------
temac #(
.P_ADD_FILT_EN(P_ADD_FILT_EN), 
.P_ADD_FILT_LIST(P_ADD_FILT_LIST), 
.P_HALF_DUPLEX(P_HALF_DUPLEX), 
.P_HOST_EN(P_HOST_EN),  
.P_SPEED_1000(P_SPEED_1000), 
.P_SPEED_10_100(P_SPEED_10_100), 
.P_TRI_SPEED(P_TRI_SPEED)
) temac_u (
// 异步复位
.reset(reset_i),

// Core Clock 
.tx_mac_clk(gtx_clk_i),           // 125MHz
.rx_mac_clk(rx_rgmii_clkInt_w),   // 125MHz（1Gbps） 25MHz(100Mbps)  2.5MHz(10Mbps)

// 速度指示
.speed_10(speed10_int_w),
.speed_100(speed100_int_w),
.speed_1000(speed1000_int_w),

//客户端发送器接口
.tx_clk_en(client_txcEn_int_w),
.tx_data(txdata8b_i),
.tx_data_en(txdata_en_i),
.tx_rdy(tx_rdy_o),
.tx_stop(tx_stop_i),
.tx_collision(tx_collision_o),
.tx_retransmit(tx_retransmit_o),
.tx_ifg_val(tx8b_ifgVal_i),

// 客户端发送器状态总线
.tx_status_vector(tx29b_statusVector_o),
.tx_status_vld(tx_statusVld_o),

// 客户端接收器接口
.rx_clk_en(client_rxcEn_int),
.rx_data(rxdata8b_o),
.rx_data_vld(rxdata_valid_o),
.rx_correct_frame(rx_correctFrame_o),
.rx_error_frame(rx_errorFrame_o),

// 客户接收器状态总线
.rx_status_vector(rx27b_statusVector_o),
.rx_status_vld(rx_statusVld_o),

// 流控接口
.pause_req(pause_req_i),
.pause_val(pause16b_val_i),
.pause_source_addr(pause48b_sourceAddr_i),

// 默认单播地址值
.unicast_addr(unicast48b_address_i), 

// 主机管理接口(AXI4-Lite总线)
.s_axi_aclk(sAXI_aclk_i), 
.s_axi_awaddr(sAXI8b_awaddr_i),     //input  wire [7:0]     
.s_axi_awvalid(sAXI_awvalid_i),     //input  wire             
.s_axi_awready(sAXI_awready_o),     //output wire             
.s_axi_wdata(sAXI32b_wdata_i),      //input  wire [31:0]     
.s_axi_wvalid(sAXI_wvalid_i),       //input  wire             
.s_axi_wready(sAXI_wready_o),       //output wire             
.s_axi_bresp(sAXI2b_bresp_o),       //output wire [1:0]     
.s_axi_bvalid(sAXI_bvalid_o),       //output wire             
.s_axi_bready(sAXI_bready_i),       //input  wire             
.s_axi_araddr(sAXI8b_araddr_i),     //input  wire [7:0]     
.s_axi_arvalid(sAXI_arvalid_i),     //input  wire             
.s_axi_arready(sAXI_arready_o),     //output wire             
.s_axi_rdata(sAXI32b_rdata_o),      //output wire [31:0]     
.s_axi_rresp(sAXI2b_rresp_o),       //output wire [1:0]     
.s_axi_rvalid(sAXI_rvalid_o),       //output wire             
.s_axi_rready(sAXI_rready_i),       //input  wire

//向量配置总线
.mac_cfg_vector(mac20b_cfgVector_i),

// gmii/mii 接口
.gmii_tx_clken(gmii_txcEn_int_w),
.gmii_txd(gmii8b_txdInt_w),
.gmii_tx_en(gmii_txenInt_w),
.gmii_tx_er(gmii_txerInt_w),
.gmii_crs(gmii_crsInt_w),
.gmii_col(gmii_colInt_w),
.gmii_rxd(gmii8b_rxdInt_w),
.gmii_rx_vld(gmii_rxdvInt_w),
.gmii_rx_er(gmii_rxerInt_w),

// MDIO接口
.mdio_clk(mdio_clk_o),
.mdio_oen(mdio_oen_o), //mdio输出使能（三态控制）
.mdio_out(mdio_o),
.mdio_in(mdio_i)
);

//===================================================================================
// 用于chipwatcher 抓 环回数据 临时逻辑
//==================================================================================
// gmii/mii Interface
//--------------------------
reg gmiiCW_tx_en;       /*synthesis keep=true*/       
reg gmiiCW_tx_er;       /*synthesis keep=true*/      
reg [7:0] gmiiCW8b_txd; /*synthesis keep=true*/      

/*
reg gmiiCW_rx_dv;       //synthesis keep=true
reg gmiiCW_rx_er;       //synthesis keep=true    
reg [7:0] gmiiCW8b_rxd; //synthesis keep=true   

// Receiver Interface
//--------------------------
reg [7:0] rxCW8b_data;   //synthesis keep=true
reg rxCW_data_valid;     //synthesis keep=true
reg rxCW_correct_frame;  //synthesis keep=true
reg rxCW_error_frame;    //synthesis keep=true
*/

//  Transmitter Interface
//-----------------------------
reg [7:0] txCW8b_data;  /*synthesis keep=true*/
reg txCW_data_en;       /*synthesis keep=true*/
reg txCW_rdy;           /*synthesis keep=true*/
reg txCW_stop;          /*synthesis keep=true*/
reg txCW_collision;     /*synthesis keep=true*/
reg txCW_retransmit;    /*synthesis keep=true*/
   
always@(posedge gtx_clk_i) begin
  if (tx_reset_w == 1) begin
    gmiiCW_tx_en <= 1'h0;
    gmiiCW_tx_er <= 1'b0;
    gmiiCW8b_txd <= 8'b0;
  end
  else if(gmii_txcEn_int_w) begin
    gmiiCW_tx_en <= gmii_txenInt_w;
    gmiiCW_tx_er <= gmii_txerInt_w;
    gmiiCW8b_txd <= gmii8b_txdInt_w;
  end
end

/*  
always@(posedge rx_rgmii_clkInt_w) begin
  if (rx_reset_w == 1) begin
    gmiiCW_rx_dv <= 1'h0;
    gmiiCW_rx_er <= 1'b0;
    gmiiCW8b_rxd <= 8'b0;
  end
  else begin
    gmiiCW_rx_dv <= gmii_rxdvInt_w;
    gmiiCW_rx_er <= gmii_rxerInt_w;
    gmiiCW8b_rxd <= gmii8b_rxdInt_w;
  end
end
*/

always@(posedge gtx_clk_i) begin
  if(reset_i == 1) begin
    txCW8b_data <= 8'b0;
    txCW_data_en <= 1'b0;
    txCW_rdy <= 1'b0;
    txCW_stop <= 1'b0;
    txCW_collision <= 1'b0;
    txCW_retransmit <= 1'b0;
  end
  else if(client_txcEn_int_w) begin
    txCW8b_data <= txdata8b_i;
    txCW_data_en <= txdata_en_i;
    txCW_rdy <= tx_rdy_o;
    txCW_stop <= tx_stop_i;
    txCW_collision <= tx_collision_o;
    txCW_retransmit <= tx_retransmit_o;
  end
end

/*  
always @(posedge rx_rgmii_clkInt_w) begin
  if (reset_i == 1) begin
    rxCW8b_data <= 8'b0;
    rxCW_data_valid <= 1'b0;
    rxCW_correct_frame <= 1'b0;
    rxCW_error_frame <= 1'b0;
  end
  else begin
    rxCW8b_data <= rxdata8b_o;
    rxCW_data_valid <= rxdata_valid_o;
    rxCW_correct_frame <= rx_correctFrame_o;
    rxCW_error_frame <= rx_errorFrame_o;
  end
end
*/

//=========================================================================================
//统计gmii接口实际发送出去包的个数 临时逻辑
//=========================================================================================
 reg [19:0] packetCW20b_cnt;  /*synthesis keep=true*/
 
always@(posedge gtx_clk_i) begin
  if (tx_reset_w == 1) begin
    packetCW20b_cnt <= 20'h0;
  end
  else if((!gmii_txenInt_w) && gmiiCW_tx_en) begin
    packetCW20b_cnt <= packetCW20b_cnt + 1;
  end
end

endmodule
